<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8">
	<link rel="icon" href="/favicon.ico" type="image/x-icon" />
	<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
	<title>接口数据转换</title>
	<link rel="stylesheet" href="/static/element-ui.css">

	<script src="/static/vue.js"></script>
	<script src="/static/element-ui.js"></script>
	<script src="/static/axios.min.js"></script>
</head>

<body>
	<div id="app">
		<el-breadcrumb separator-class="el-icon-arrow-right">
			<el-breadcrumb-item>
				<el-link type="primary" href="/">接口列表</el-link>
			</el-breadcrumb-item>
			<el-breadcrumb-item>
				<el-link>接口详情</el-link>
			</el-breadcrumb-item>
		</el-breadcrumb>
		<el-row :gutter="5">
			<el-col span="9" style="text-align: right;">
				<el-upload drag action="leftJson" accept=".json" :show-file-list="false" :http-request="uploadFile">
					<i class="el-icon-upload"></i>
					<div class="el-upload__text">
						将文件拖到此处，或<em>点击上传</em>。
						只能上传 json 文件
					</div>
				</el-upload>
			</el-col>
			<el-col span="6" style="text-align: center;">
				<el-button icon="el-icon-arrow-left" @click="exportJson('leftJson')">导出</el-button>
				<el-button @click="exportJson('rightJson')">导出
					<i class="el-icon-arrow-right el-icon--right"></i>
				</el-button>
			</el-col>
			<el-col span="9">
				<el-upload drag action="rightJson" accept=".json" :show-file-list="false" :http-request="uploadFile">
					<i class="el-icon-upload"></i>
					<div class="el-upload__text">
						将文件拖到此处，或<em>点击上传</em>。
						只能上传 json 文件
					</div>
				</el-upload>
			</el-col>
			<el-col span="10">
				<el-row :gutter="5">
					<el-col span="6">接口名称：</el-col>
					<el-col span="18">
						<el-input v-model="leftJson.title" placeholder="接口名称"></el-input>
					</el-col>
					<el-col span="6">接口地址：</el-col>
					<el-col span="18">
						<el-input v-model="leftJson.path" placeholder="接口地址"></el-input>
					</el-col>
				</el-row>
			</el-col>
			<el-col span="10" offset="4">
				<el-row :gutter="5">
					<el-col span="6">接口名称：</el-col>
					<el-col span="18">
						<el-input v-model="rightJson.title" placeholder="接口名称"></el-input>
					</el-col>
					<el-col span="6">接口地址：</el-col>
					<el-col span="18">
						<el-input v-model="rightJson.path" placeholder="接口地址"></el-input>
					</el-col>
				</el-row>
			</el-col>
			<el-col span="14">
				<el-row>
					<el-col span="24">
						<el-button type="text" size="medium">请求参数</el-button>
					</el-col>
					<el-col span="24">
						<el-table ref="leftRequestTable" size="mini" :data="leftJson.requestJson" row-key="num" default-expand-all
							border highlight-current-row>
							<el-table-column prop="num" label="序号" align="center" width="80"></el-table-column>
							<el-table-column v-for="(v,i) in columns" :prop="v.field" :label="v.title" :width="v.width"
								header-align="center" show-overflow-tooltip>
								<template slot-scope="scope">
									<span v-show="scope.row.isEdit">
										<el-input size="mini" placeholder="请输入内容" v-model="editJson.data[v.field]" />
									</span>
									<span v-show="!scope.row.isEdit">{{scope.row[v.field]}}</span>
								</template>
							</el-table-column>
							<el-table-column label="操作" width="115" align="center">
								<template slot-scope="scope">
									<el-popover placement="top" trigger="hover" v-if="!scope.row.isEdit">
										<el-link @click="addRow('leftJson', 'requestJson', scope.row, 'up')">
											兄弟节点（上方）
										</el-link><br />
										<el-link @click="addRow('leftJson', 'requestJson', scope.row, 'down')">
											兄弟节点（下方）
										</el-link><br />
										<el-link v-if="scope.row.type == 'object'"
											@click="addRow('leftJson', 'requestJson', scope.row, 'child')">
											子节点
										</el-link>
										<el-link type="success" slot="reference">添加</el-link>
									</el-popover>
									<el-link type="primary" @click="editRow('leftJson', 'requestJson', scope.row, scope.$index, true)">
										{{scope.row.isEdit ? '保存' : '修改'}}
									</el-link>
									<el-link v-if="!scope.row.isEdit" type="danger"
										@click="removeRow('leftJson', leftJson.requestJson, scope.row)">删除</el-link>
									<el-link v-else @click="editRow('leftJson', 'requestJson', scope.row, scope.$index, false)">
										取消
									</el-link>
								</template>
							</el-table-column>
							<el-table-column prop="memo" label="转换逻辑" align="center" show-overflow-tooltip>
								<template slot-scope="{row}">
									<span v-if="row.isEdit">
										<el-input size="mini" placeholder="请输入内容" v-model="editJson.data.memo" />
									</span>
									<span v-else>{{row.memo}}</span>
								</template>
							</el-table-column>
							<template slot="empty">
								<el-link type="success" @click="addRow('leftJson', 'requestJson', {}, 'down')">添加
								</el-link>
							</template>
						</el-table>
					</el-col>
					<el-col span="24">
						<el-button type="text" size="medium">返回参数</el-button>
					</el-col>
					<el-col span="24">
						<el-table ref="leftResponseTable" size="mini" :data="leftJson.responseJson" row-key="num" default-expand-all
							border highlight-current-row>
							<el-table-column prop="num" label="序号" align="center" width="80"></el-table-column>
							<el-table-column v-for="(v,i) in columns" :prop="v.field" :label="v.title" :width="v.width"
								header-align="center" show-overflow-tooltip>
								<template slot-scope="scope">
									<span v-show="scope.row.isEdit">
										<el-input size="mini" placeholder="请输入内容" v-model="editJson.data[v.field]" />
									</span>
									<span v-show="!scope.row.isEdit">{{scope.row[v.field]}}</span>
								</template>
							</el-table-column>
							<el-table-column label="操作" width="115" align="center">
								<template slot-scope="scope">
									<el-popover placement="top" trigger="hover" v-if="!scope.row.isEdit">
										<el-link @click="addRow('leftJson', 'responseJson', scope.row, 'up')">
											兄弟节点（上方）
										</el-link><br />
										<el-link @click="addRow('leftJson', 'responseJson', scope.row, 'down')">
											兄弟节点（下方）
										</el-link><br />
										<el-link v-if="scope.row.type == 'object'"
											@click="addRow('leftJson', 'responseJson', scope.row, 'child')">
											子节点
										</el-link>
										<el-link type="success" slot="reference">添加</el-link>
									</el-popover>
									<el-link type="primary" @click="editRow('leftJson', 'responseJson', scope.row, scope.$index, true)">
										{{scope.row.isEdit ? '保存' : '修改'}}
									</el-link>
									<el-link v-if="!scope.row.isEdit" type="danger"
										@click="removeRow('leftJson', leftJson.responseJson, scope.row)">删除</el-link>
									<el-link v-else @click="editRow('leftJson', 'responseJson', scope.row, scope.$index, false)">
										取消
									</el-link>
								</template>
							</el-table-column>
							<el-table-column prop="memo" label="转换逻辑" align="center" show-overflow-tooltip>
								<template slot-scope="{row}">
									<span v-if="row.isEdit">
										<el-input size="mini" placeholder="请输入内容" v-model="editJson.data.memo" />
									</span>
									<span v-else>{{row.memo}}</span>
								</template>
							</el-table-column>
							<template slot="empty">
								<el-link type="success" @click="addRow('leftJson', 'responseJson', {}, 'down')">添加
								</el-link>
							</template>
						</el-table>
					</el-col>
				</el-row>
			</el-col>
			<el-col span="10">
				<el-row>
					<el-col span="24">
						<el-button type="text" size="medium">请求参数</el-button>
					</el-col>
					<el-col span="24">
						<el-table ref="rightRequestTable" size="mini" :data="rightJson.requestJson" row-key="num" default-expand-all
							border highlight-current-row>
							<el-table-column prop="num" label="序号" align="center" width="80"></el-table-column>
							<el-table-column label="操作" width="115" align="center">
								<template slot-scope="scope">
									<el-popover placement="top" trigger="hover" v-if="!scope.row.isEdit">
										<el-link @click="addRow('rightJson', 'requestJson', scope.row, 'up')">
											兄弟节点（上方）
										</el-link><br />
										<el-link @click="addRow('rightJson', 'requestJson', scope.row, 'down')">
											兄弟节点（下方）
										</el-link><br />
										<el-link v-if="scope.row.type == 'object'"
											@click="addRow('rightJson', 'requestJson', scope.row, 'child')">
											子节点
										</el-link>
										<el-link type="success" slot="reference">添加</el-link>
									</el-popover>
									<el-link type="primary" @click="editRow('rightJson', 'requestJson', scope.row, scope.$index, true)">
										{{scope.row.isEdit ? '保存' : '修改'}}
									</el-link>
									<el-link v-if="!scope.row.isEdit" type="danger"
										@click="removeRow('rightJson', rightJson.requestJson, scope.row)">
										删除
									</el-link>
									<el-link v-else @click="editRow('rightJson', 'requestJson', scope.row, scope.$index, false)">
										取消
									</el-link>
								</template>
							</el-table-column>
							<el-table-column v-for="(v,i) in columns" :prop="v.field" :label="v.title" :width="v.width"
								header-align="center" show-overflow-tooltip>
								<template slot-scope="scope">
									<span v-show="scope.row.isEdit">
										<el-input size="mini" placeholder="请输入内容" v-model="editJson.data[v.field]" />
									</span>
									<span v-show="!scope.row.isEdit">{{scope.row[v.field]}}</span>
								</template>
							</el-table-column>
							<template slot="empty">
								<el-link type="success" @click="addRow('rightJson', 'requestJson', {}, 'down')">添加
								</el-link>
							</template>
						</el-table>
					</el-col>
					<el-col span="24">
						<el-button type="text" size="medium">返回参数</el-button>
					</el-col>
					<el-col span="24">
						<el-table ref="rightResponseTable" size="mini" :data="rightJson.responseJson" row-key="num"
							default-expand-all border highlight-current-row>
							<el-table-column prop="num" label="序号" align="center" width="80"></el-table-column>
							<el-table-column label="操作" width="115" align="center">
								<template slot-scope="scope">
									<el-popover placement="top" trigger="hover" v-if="!scope.row.isEdit">
										<el-link @click="addRow('rightJson', 'requestJson', scope.row, 'up')">
											兄弟节点（上方）
										</el-link><br />
										<el-link @click="addRow('rightJson', 'requestJson', scope.row, 'down')">
											兄弟节点（下方）
										</el-link><br />
										<el-link v-if="scope.row.type == 'object'"
											@click="addRow('rightJson', 'requestJson', scope.row, 'child')">
											子节点
										</el-link>
										<el-link type="success" slot="reference">添加</el-link>
									</el-popover>
									<el-link type="primary" @click="editRow('rightJson', 'responseJson', scope.row, scope.$index, true)">
										{{scope.row.isEdit ? '保存' : '修改'}}
									</el-link>
									<el-link v-if="!scope.row.isEdit" type="danger"
										@click="removeRow('rightJson', rightJson.responseJson, scope.row)">删除
									</el-link>
									<el-link v-else @click="editRow('rightJson', 'responseJson', scope.row, scope.$index, false)">
										取消</el-link>
								</template>
							</el-table-column>
							<el-table-column v-for="(v,i) in columns" :prop="v.field" :label="v.title" :width="v.width"
								header-align="center" show-overflow-tooltip>
								<template slot-scope="scope">
									<span v-show="scope.row.isEdit">
										<el-input size="mini" placeholder="请输入内容" v-model="editJson.data[v.field]" />
									</span>
									<span v-show="!scope.row.isEdit">{{scope.row[v.field]}}</span>
								</template>
							</el-table-column>
							<template slot="empty">
								<el-link type="success" @click="addRow('rightJson', 'responseJson', {}, 'down')">添加
								</el-link>
							</template>
						</el-table>
					</el-col>
				</el-row>
			</el-col>
		</el-row>
		<el-dialog title="选择导入的接口" :visible.sync="dialogTableVisible">
			<el-table ref="selectImportDataTable" :data="uploadJson.tableData" row-key="index" highlight-current-row
				max-height="600" @row-click="selectRow">
				<el-table-column property="index" label="序号" width="100"></el-table-column>
				<el-table-column property="title" label="接口名称"></el-table-column>
				<el-table-column property="path" label="接口地址"></el-table-column>
			</el-table>
		</el-dialog>
	</div>
</body>
<script type="text/javascript">
	var app = new Vue({
		el: '#app',
		data: {
			columns: [
				{ field: 'columnName', title: '名称' },
				{ field: 'type', title: '类型', width: 80 },
				{ field: 'required', title: '必须', width: 60 },
				{ field: 'description', title: '备注' }
			],
			id: getQueryString('id'),
			leftJson: {
				title: '',
				path: '',
				requestJson: [],
				responseJson: []
			},
			rightJson: {
				title: '',
				path: '',
				requestJson: [],
				responseJson: []
			},
			editJson: {
				isEdit: false,
				data: {}
			},
			debouncedStore: debounce(500, storeJson),
			dialogTableVisible: false,
			uploadJson: {
				originalData: [],
				tableData: []
			}
		},
		watch: {
			'leftJson.title': function (newVal, oldVal) {
				var key = 'leftJson'
				app.debouncedStore(key, app[key])
			},
			'leftJson.path': function (newVal, oldVal) {
				var key = 'leftJson'
				app.debouncedStore(key, app[key])
			},
			'rightJson.title': function (newVal, oldVal) {
				var key = 'rightJson'
				app.debouncedStore(key, app[key])
			},
			'rightJson.path': function (newVal, oldVal) {
				var key = 'rightJson'
				app.debouncedStore(key, app[key])
			}
		},
		methods: {
			loadData: function (id) {
				if (!id) { return }
				var app = this
				axios.get('/api/interfaces/' + id).then(function (response) {
					var storeJson = response.data
					app.id = storeJson.Id
					app.name = storeJson.Name
					app.leftJson = JSON.parse(storeJson.PrimaryJson || '{}') || app.leftJson
					app.rightJson = JSON.parse(storeJson.AssistantJson || '{}') || app.rightJson
				});
			},
			uploadFile: function (param) {
				if (window.FileReader) {
					var reader = new FileReader();
					reader.onloadend = function (evt) {
						if (evt.target.readyState == FileReader.DONE) {
							var key = param.action
							var originalData = JSON.parse(evt.target.result)
							// 判断文件接口个数,如果大于1,则弹出选择框以供选择导入的接口
							if (originalData.length > 1 || originalData[0].list.length > 1) {
								app.dialogTableVisible = true
								app.uploadJson.originalData = originalData
								var d = []
								var rowIndex = 0
								for (var index in originalData) {
									var row = originalData[index]
									originalData.index = ++rowIndex
									var children = []
									d.push({ index: rowIndex, title: row.name, path: '', children: children })
									for (var childIndex in row.list) {
										var child = row.list[childIndex]
										child.index = ++rowIndex
										children.push({ index: rowIndex, title: child.title, path: child.path })
									}
								}
								app.uploadJson.tableData = d
								app.uploadJson.key = key
								app.$nextTick(function () {
									app.$refs.selectImportDataTable.toggleRowExpansion(d[0], d.length === 1)
								})
							} else if (originalData.length > 0) {
								// 若只有一个接口,则默认导入第一个
								var json = originalData[0].list[0]
								importData(key, json)
							} else {
								app.$message.warning('导入接口为空');
							}
						}
					};
					reader.readAsText(param.file, 'utf-8');
				}
			},
			importData(key, json) {
				var requestJson
				if (json.req_body_other) {
					requestJson = cv(JSON.parse(json.req_body_other))
				} else {
					requestJson = []
					for (var index in json.req_params) {
						var param = json.req_params[index]
						requestJson.push({
							columnName: param.name,
							type: '',
							required: '',
							description: param.desc
						})
					}
				}
				app[key] = {
					title: json.title,
					path: json.path,
					requestJson: requestJson,
					responseJson: cv(JSON.parse(json.res_body))
				}
				sort(app[key].responseJson, sort(app[key].requestJson))
				storeJson()
			},
			selectRow(row, column, event) {
				if (row.children != undefined) {
					return app.$refs.selectImportDataTable.toggleRowExpansion(row)
				} else {
					var originalData = app.uploadJson.originalData
					for (var index in originalData) {
						var data = originalData[index]
						for (var childIndex in data.list) {
							var child = data.list[childIndex]
							if (row.index == child.index) {
								app.importData(app.uploadJson.key, child)
								app.dialogTableVisible = false
								app.uploadJson.originalData = []
								app.uploadJson.tableData = []
								app.uploadJson.key = undefined
								return
							}
						}
					}

				}
			},
			// 添加行
			addRow(key, rowsKey, clickRow, direction) {
				// 点击修改 判断是否已经保存所有操作
				if (app.editJson.isEdit) {
					return app.$message.warning('请先保存当前编辑项');
				}
				app.editJson.data = { isEdit: true }
				app.editJson.isEdit = true
				var clickRowNum = clickRow.num

				var cc = function (newRows, rows) {
					if (direction == 'up') {
						for (var index in rows) {
							var row = rows[index]
							if (row.num == clickRowNum) {
								newRows.push({ isEdit: true, isNew: true })
							}
							newRows.push(row)
							if (row.children && row.children.length > 0) {
								row.children = cc([], row.children)
							}
						}
					} else if (direction == 'down') {
						for (var index in rows) {
							var row = rows[index]
							newRows.push(row)
							if (row.num == clickRowNum) {
								newRows.push({ isEdit: true, isNew: true })
							}
							if (row.children && row.children.length > 0) {
								row.children = cc([], row.children)
							}
						}
					} else if (direction == 'child') {
						for (var index in rows) {
							var row = rows[index]
							newRows.push(row)
							row.children = cc([], row.children || [])
							if (row.num == clickRowNum) {
								row.children.push({ isEdit: true, isNew: true })
							}
						}
					}
					return newRows
				}
				var oldRows = app[key][rowsKey]
				var newRows = []
				if (oldRows && oldRows.length > 0) {
					newRows = cc([], oldRows)
				} else {
					newRows.push({ num: 0, isEdit: true, isNew: true })
				}
				app[key][rowsKey] = newRows
				sort(app[key].responseJson, sort(app[key].requestJson))
			},
			// 编辑行数据
			editRow(key, rowsKey, row, index, isEdit) {
				// 是否是取消操作
				if (!isEdit) {
					app.editJson.data = {}
					app.editJson.isEdit = false
					row.isEdit = false
					if (row.isNew) {
						app.removeRow(key, app[key][rowsKey], row)
					}
					return false
				}
				// 点击修改 判断是否已经保存所有操作
				if (app.editJson.isEdit && !row.isEdit) {
					return app.$message.warning('请先保存当前编辑项');
				}
				if (row.isEdit) {
					// 提交数据
					let data = JSON.parse(JSON.stringify(app.editJson.data));
					for (let k in data) row[k] = data[k];
					delete row.isEdit
					delete row.isNew
					storeJson()
					app.editJson.data = {}
					app.editJson.isEdit = false
				} else {
					app.editJson.data = JSON.parse(JSON.stringify(row))
					app.editJson.isEdit = true
					row.isEdit = true
				}
			},
			removeRow(key, data, row) {
				if (row.isEdit) {
					return app.$message.warning('请先保存当前编辑项');
				}
				var cc = function (d) {
					for (var index in d) {
						var dd = d[index]
						if (dd.num == row.num) {
							d.splice(index, 1)
							break
						}
						if (dd.children && dd.children.length > 0) {
							cc(dd.children)
						}
					}
				}
				cc(data)
				sort(app[key].responseJson, sort(app[key].requestJson))
				storeJson()
			},
			exportJson(key) {
				var cc = function (data) {
					if (data.type === 'array') {
						var o = {
							type: 'object'
						}
						if (data.children && data.children.length > 0) {
							var properties = {}
							var required = []
							for (var index in data.children) {
								var children = data.children[index]
								properties[children.columnName] = cc(children)
								if (children.required) {
									required.push(children.columnName)
								}
							}
							o.required = required
							o.properties = properties
						}
						return {
							type: data.type,
							items: o,
							description: data.description
						}
					} else {
						var o = {
							type: data.type,
							description: data.description
						}
						if (data.children && data.children.length > 0) {
							var properties = {}
							var required = []
							for (var index in data.children) {
								var children = data.children[index]
								properties[children.columnName] = cc(children)
								if (children.required) {
									required.push(children.columnName)
								}
							}
							o.properties = properties
							o.required = required
						}
						return o
					}
				}

				var json = app[key]
				var requestJson = json.requestJson
				var reqBodyOther = {
					"type": "object",
					"properties": {},
					"title": json.title + "请求信息",
					"required": []
				}
				for (var index in requestJson) {
					var d = requestJson[index]
					reqBodyOther.properties[d.columnName] = cc(d)
					if (d.required) {
						reqBodyOther.required.push(d.columnName)
					}
				}
				var responseJson = json.responseJson
				var resBody = {
					"type": "object",
					"properties": {},
					"title": json.title + "返回信息",
					"required": []
				}
				for (var index in responseJson) {
					var d = responseJson[index]
					resBody.properties[d.columnName] = cc(d)
					if (d.required) {
						resBody.required.push(d.columnName)
					}
				}
				var outJson = [
					{
						"index": 0,
						"name": json.title,
						"desc": null,
						"add_time": new Date().getTime() / 1000,
						"up_time": new Date().getTime() / 1000,
						"list": [
							{
								"query_path": {
									"path": json.path,
									"params": []
								},
								"edit_uid": 0,
								"status": "undone",
								"type": "static",
								"req_body_is_json_schema": true,
								"res_body_is_json_schema": true,
								"api_opened": true,
								"index": 0,
								"tag": [],
								"method": "POST",
								"title": json.title,
								"path": json.path,
								"req_params": [],
								"res_body_type": "json",
								"req_query": [],
								"req_headers": [
									{
										"required": "1",
										"name": "Content-Type",
										"value": "application/json"
									}
								],
								"req_body_form": [],
								"desc": "<p><br data-tomark-pass=\"\"><br>\n<br data-tomark-pass=\"\"></p>\n",
								"markdown": "<br>\n<br>\n",
								"req_body_other": JSON.stringify(reqBodyOther),
								"req_body_type": "json",
								"res_body": JSON.stringify(resBody),
								"add_time": new Date().getTime() / 1000,
								"up_time": new Date().getTime() / 1000,
								"__v": 0
							}
						]
					}
				]
				var blob = new Blob([JSON.stringify(outJson)])
				var a = document.createElement('a')
				a.download = json.title + '.json'
				a.href = URL.createObjectURL(blob)
				a.click()
				URL.revokeObjectURL(blob)
			}
		},
		created: function () {
			this.loadData(this.id)
		}
	});
	function sort(rows, num) {
		num = num === undefined ? 0 : num
		for (var index in rows) {
			var row = rows[index]
			row.num = ++num
			if (row.children && row.children.length > 0) {
				num = sort(row.children, num)
			}
		}
		return num
	}
	function cv(data) {
		if (!data) { return undefined }
		data = (data.type === 'array' ? data.items : data)
		var requiredColumns = data.required
		var requiredColumnMap = {}
		for (var index in requiredColumns) {
			requiredColumnMap[requiredColumns[index]] = true
		}
		var resData = []
		var properties = data.properties
		for (var key in properties) {
			var column = properties[key]
			resData.push({
				columnName: key,
				type: column.type,
				required: requiredColumnMap[key] ? 'Y' : 'N',
				description: column.description || column.title,
				children: cv(column)
			})
		}
		return resData
	}
	function storeJson() {
		axios.post('/api/interfaces', {
			Id: app.id,
			Name: app.leftJson.title || app.rightJson.title,
			PrimaryJson: JSON.stringify(app.leftJson),
			AssistantJson: JSON.stringify(app.rightJson)
		}).then(function (response) {
			var storeJson = response.data
			app.id = storeJson.Id
		});
	}
	function debounce(idle, action) {
		var last
		return function () {
			var ctx = this, args = arguments
			clearTimeout(last)
			last = setTimeout(function () {
				action.apply(ctx, args)
			}, idle)
		}
	}
	function getQueryString(name) {
		let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
		let r = window.location.search.substr(1).match(reg);
		if (r != null) {
			return unescape(r[2]);
		};
		return null;
	}
</script>

</html>